package controller

import (
	"github.com/ahmetb/go-linq/v3"
	"github.com/fatih/color"
	"github.com/gin-gonic/gin"
	"github.com/ifnk/micro-blog/internal/blog/dto/user_dto"
	"github.com/ifnk/micro-blog/internal/blog/global"
	"github.com/ifnk/micro-blog/internal/blog/middleware"
	"github.com/ifnk/micro-blog/internal/pkg/base"
	response "github.com/ifnk/micro-blog/internal/pkg/http"
	"github.com/ifnk/micro-blog/internal/pkg/jwt"
	"github.com/ifnk/micro-blog/internal/pkg/utils"
	"github.com/ifnk/micro-blog/protobuf/permission_pb"
	"github.com/infobloxopen/atlas-app-toolkit/query"
	"go.uber.org/zap"
	"strconv"
	"strings"
)

type UserPageRes struct {
	Total int32
	Items []permission_pb.UserORM
}
type UserDto struct {
	User      permission_pb.UserORM
	Authority permission_pb.AuthorityORM
}

func InitUserController(r *gin.RouterGroup) {
	// 给 一个 users 的路由组 (http://localhost:6666/api/user)
	api := r.Group("/user")

	api.POST("login", login)
	api.POST("register", register)
	api.POST("info", getUserInfoByToken)
	api.POST("ids", getUsersByIds)
	api.POST("query", queryAll)
	api.POST("", createUser)
	api.PUT("/:id", updateUser)
	api.DELETE("/:id", deleteUser)
	// 这个 要 使用 jwt 和 casbin 中间件(在这个之前的不用验证,之后的需要验证啦)
	api.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())

	api.GET("", getUsers)
	api.GET("/:id", getUser)
	api.POST("test", test)
	api.POST("changePassword", changePassword)
	api.POST("setUserAuthority", setUserAuthority)
}

func queryAll(c *gin.Context) {
	var request permission_pb.ListUserRequest
	err := c.ShouldBindJSON(&request)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	userRes, err := global.UserClient.List(c, &request)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var userORMS []permission_pb.UserORM
	for _, item := range userRes.GetResults() {
		orm, err := item.ToORM(c)
		if err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
		userORMS = append(userORMS, orm)
	}

	response.OkWithData(userORMS, c)
}

func getUsersByIds(c *gin.Context) {
	ids := []float64{1}
	request := permission_pb.ListUserRequest{
		Filter: &query.Filtering{
			Root: &query.Filtering_NumberArrayCondition{
				NumberArrayCondition: &query.NumberArrayCondition{
					FieldPath: []string{"id"},
					Values:    ids,
				},
			},
		},
	}
	userRes, err := global.UserClient.List(c, &request)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var userORMS []permission_pb.UserORM
	for _, item := range userRes.GetResults() {
		orm, err := item.ToORM(c)
		if err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
		userORMS = append(userORMS, orm)
	}

	response.OkWithData(userORMS, c)

}

func getUserInfoByToken(c *gin.Context) {
	var tokenParams user_dto.TokenParams
	_ = c.ShouldBindJSON(&tokenParams)
	// 根据 token 获取 claims 找到userId
	j := jwt.NewJwt(global.Logger, global.Conf)
	// parseToken 解析token包含的信息
	claims, err := j.ParseToken(tokenParams.Token)
	if err != nil {
		if err == jwt.TokenExpired {
			response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c)
			return
		}
		response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c)
		return
	}
	id := claims.ID
	read, err := global.UserClient.Read(c, &permission_pb.ReadUserRequest{Id: uint64(id)})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	orm, _ := read.Result.ToORM(c)
	response.OkWithData(orm, c)

}

func login(c *gin.Context) {
	var l user_dto.Login
	_ = c.ShouldBindJSON(&l)
	if err := utils.Verify(l, utils.LoginVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	userRes, err := global.UserClient.GetUserByName(c, &permission_pb.GetUserByNameRequest{Payload: l.Username})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	userOrm, _ := userRes.GetResult().ToORM(c)
	color.Blue("l.Password -> %+v", l.Password)
	color.Blue("utils.MD5V([]byte(l.Password)) -> %+v", utils.MD5V([]byte(l.Password)))
	color.Blue("userOrm.Password -> %+v", userOrm.Password)
	if utils.MD5V([]byte(l.Password)) != userOrm.Password {
		response.FailWithMessage("密码错误", c)
		return
	}

	tokenNext(c, userOrm)
}

func tokenNext(c *gin.Context, user permission_pb.UserORM) {
	var authorityIdStrs []string
	linq.From(user.AuthorityIds).
		Select(func(c interface{}) interface{} {
			return strconv.Itoa(int(c.(int64)))
		}).
		ToSlice(&authorityIdStrs)
	jwtManager := jwt.NewJwt(global.Logger, global.Conf)
	claims := jwtManager.CreateClaims(jwt.BaseClaims{
		ID:           uint(user.Id),
		Username:     user.Username,
		NickName:     user.NickName,
		AuthorityIds: authorityIdStrs,
	})

	token, err := jwtManager.CreateToken(claims)
	if err != nil {
		global.Logger.Error("获取token失败!", zap.Error(err))
		response.FailWithMessage("获取token失败", c)
		return
	}
	response.OkWithDetailed(user_dto.LoginResponse{
		User:      user,
		Token:     token,
		ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
	}, "登录成功", c)

}

func changePassword(c *gin.Context) {
	var user user_dto.ChangePasswordStruct
	_ = c.ShouldBindJSON(&user)
	if err := utils.Verify(user, utils.ChangePasswordVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	u := &permission_pb.UserORM{Username: user.Username, Password: user.Password}
	pb, _ := u.ToPB(c)
	_, err := global.UserClient.ChangePassword(c, &permission_pb.ChangePasswordRequest{Payload: &pb, NewPassword: user.NewPassword})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithMessage("修改成功", c)
}

func register(c *gin.Context) {
	var r user_dto.Register
	_ = c.ShouldBindJSON(&r)
	color.Blue("r -> %+v", r)
	err := utils.Verify(r, utils.RegisterVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	//var authorities []*permission_pb.AuthorityORM
	user := &permission_pb.UserORM{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, Email: r.Email}
	pb, err := user.ToPB(c)
	userResponse, err := global.UserClient.Register(c, &permission_pb.CreateUserRequest{Payload: &pb})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	orm, _ := userResponse.Result.ToORM(c)
	response.OkWithDetailed(orm, "注册成功", c)
}

func test(c *gin.Context) {
	res, err := global.UserClient.TestDuDu(c, &permission_pb.CreateUserRequest{})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithData(res, c)

}

func createUser(c *gin.Context) {
	var input permission_pb.User
	_ = c.ShouldBindJSON(&input)

	input.Password = utils.MD5V([]byte(input.Password))
	res, err := global.UserClient.CreateUser(c, &permission_pb.CreateUserRequest{Payload: &input})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	orm, err := res.GetResult().ToORM(c)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithData(orm, c)
}

func getUsers(c *gin.Context) {
	var params base.PageEntity
	_ = c.ShouldBindQuery(&params)
	offset := int32(params.PageIndex-1) * int32(params.PageSize)
	limit := int32(params.PageSize)
	userRes, err := global.UserClient.List(c, &permission_pb.ListUserRequest{Paging: &query.Pagination{Offset: offset, Limit: limit}})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var userORMS []permission_pb.UserORM
	for _, item := range userRes.GetResults() {
		orm, err := item.ToORM(c)
		if err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
		userORMS = append(userORMS, orm)
	}

	var total int32
	if userRes.PageInfo == nil {
		total = 0
	} else {
		total = userRes.PageInfo.Size
	}

	response.OkWithData(UserPageRes{
		Total: total,
		Items: userORMS,
	}, c)
}

func setUserAuthority(c *gin.Context) {
	var input user_dto.SetUserAuth
	_ = c.ShouldBindJSON(&input)
	if len(input.AuthorityIds) == 0 {
		response.FailWithMessage("角色列表不能为空", c)
		return
	}
	id, err := global.UserRltAuthServiceClient.ChangeByUserId(c, &permission_pb.ChangeByUserIdReq{UserId: input.UserId, AuthorityIds: input.AuthorityIds})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	color.Blue("id.Success -> %+v", id.Success)
	response.OkWithMessage("修改成功", c)

}

func updateUser(c *gin.Context) {
	var input permission_pb.UserORM
	idStr := c.Param("id")
	id, _ := strconv.Atoi(strings.TrimSpace(idStr))
	_ = c.ShouldBindJSON(&input)
	input.Id = uint64(id)
	input.Username = ""
	input.Password = ""
	pb, _ := input.ToPB(c)
	res, err := global.UserClient.Update(c, &permission_pb.UpdateUserRequest{Payload: &pb})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	orm, _ := res.GetResult().ToORM(c)
	response.OkWithData(orm, c)
}
func deleteUser(c *gin.Context) {
	idStr := c.Param("id")
	id, _ := strconv.Atoi(strings.TrimSpace(idStr))
	res, err := global.UserClient.Delete(c, &permission_pb.DeleteUserRequest{Id: uint64(id)})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithData(res, c)
}

//
func getUser(c *gin.Context) {
	idStr := c.Param("id")
	id, _ := strconv.Atoi(strings.TrimSpace(idStr))
	res, err := global.UserClient.Read(c, &permission_pb.ReadUserRequest{Id: uint64(id)})
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	orm, _ := res.GetResult().ToORM(c)
	response.OkWithData(orm, c)
}
